﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Text.RegularExpressions;
using System.IO;
using ProxyHero.Entity;
using Microsoft.Win32;
using System.Runtime.InteropServices;
using System.Security.AccessControl;

namespace ProxyHero.Common
{
    public class ProxyHelper
    {
        #region Variable
        IniHelper iniHelper;
        [DllImport("wininet.dll", SetLastError = true)]
        private static extern bool InternetSetOption(IntPtr hInternet, int dwOption, IntPtr lPBuffer, int lpdwBufferLength);

        private const int INTERNET_OPTION_REFRESH = 0x000025;
        private const int INTERNET_OPTION_SETTINGS_CHANGED = 0x000027;
        #endregion

        #region Constructors
        public ProxyHelper()
        {
            if (File.Exists(Config.ProxyIniPath))
            {
                iniHelper = new IniHelper(Config.ProxyIniPath);
                Config.UnEscape = iniHelper.read("Proxy", "UnEscape");
                Config.StartHtml = iniHelper.read("Proxy", "StartHtml");
                Config.EndHtml = iniHelper.read("Proxy", "EndHtml");
                Config.Encoding = iniHelper.read("Proxy", "Encoding");
                Config.IpRegex = iniHelper.read("Proxy", "IpRegex");
                Config.PortRegex = iniHelper.read("Proxy", "PortRegex");
                Config.AreaRegex = iniHelper.read("Proxy", "AreaRegex");
                Config.TypeRegex = iniHelper.read("Proxy", "TypeRegex");
                Config.TimeOrSpeedRegex = iniHelper.read("Proxy", "TimeOrSpeedRegex");
                Config.NextPageCutHtmlRegex = iniHelper.read("Proxy", "NextPageCutHtmlRegex");
                Config.NextPageRegex = iniHelper.read("Proxy", "NextPageRegex");
                Config.NextPageUrlEnable = iniHelper.read("Proxy", "NextPageUrlEnable");
                Config.NextPageValidate = iniHelper.read("Proxy", "NextPageValidate");
            }
            else
            {
                throw new Exception(Config.ProxyIniPath + " not found!");
            }

            if (File.Exists(Config.ConfigPath))
            {
                Config.LocalConfig = XmlHelper.XmlDeserialize(
                    Config.ConfigPath, 
                    typeof(ConfigEntity)) as ConfigEntity;
            }

        }
        #endregion

        #region Public Methods
        private DataTable InitDataTable()
        {
            DataTable dt = new DataTable();

            dt.Columns.Add("IP");
            dt.Columns.Add("Port");
            dt.Columns.Add("Area");
            dt.Columns.Add("Type");
            dt.Columns.Add("TestTime");
            dt.Columns.Add("Speed", typeof(double));

            return dt;
        }

        /// <summary>
        /// 获取代理列表
        /// </summary>
        /// <returns></returns>
        public DataTable GetProxyList()
        {
            DataTable dt = InitDataTable();

            try
            {
                int intNextPage = 0;

                HttpUility.HttpHelper httpHelper = new HttpUility.HttpHelper();

                if (Config.LocalConfig.HttpSetting != null)
                {
                    httpHelper.HttpSetting = Config.LocalConfig.HttpSetting;
                }
                else
                {
                    httpHelper.HttpSetting.Timeout = 60 * 1000;
                }
                GetData:
                string result = httpHelper.GetHtml(httpHelper.doGetNoProxy(Config.ProxyListUrl), Encoding.GetEncoding(Config.Encoding));

                if (!Config.StartHtml.Equals("") && !Config.EndHtml.Equals(""))
                {
                    result = StringHelper.GetMidString(result, Config.StartHtml, Config.EndHtml);
                }

                Regex regex = new Regex(Config.IpRegex);
                MatchCollection matchesIp = regex.Matches(result);

                regex = new Regex(Config.PortRegex);
                MatchCollection matchesPort = regex.Matches(result);

                regex = new Regex(Config.AreaRegex);
                MatchCollection matchesArea = regex.Matches(result);

                regex = new Regex(Config.TypeRegex);
                MatchCollection matchesType = regex.Matches(result);

                regex = new Regex(Config.TimeOrSpeedRegex);
                MatchCollection matchesTimeOrSpeed = regex.Matches(result);

                if (matchesIp.Count == matchesPort.Count)
                {
                    #region AddData
                    for (int i = 0; i < matchesIp.Count; i++)
                    {
                        DataRow dr = dt.NewRow();

                        if (Config.UnEscape.Equals("1"))
                        {
                            dr["IP"] = Microsoft.JScript.GlobalObject.unescape(
                                matchesIp[i].Groups["IP"].Value).Replace(
                                "self.document.writeln(\"",
                                "").Replace("\");","");
                        }
                        else
                        {
                            dr["IP"] = matchesIp[i].Groups["IP"].Value;
                        }
                        dr["Port"] = matchesPort[i].Groups["Port"].Value;
                        if (matchesArea.Count == matchesIp.Count && matchesArea.Count >= i)
                        {
                            dr["Area"] = matchesArea[i].Groups["Area"].Value.ToLower().Replace("proxycn", "");
                        }
                        if (dr["Area"].ToString() == "")
                        {
                            IpHelper ih = new IpHelper(dr["IP"].ToString());
                            dr["Area"] = ih.Location;
                        }
                        if (matchesType.Count == matchesIp.Count && matchesType.Count >= i)
                        {
                            dr["Type"] = matchesType[i].Groups["Type"].Value;
                        }
                        else
                        {
                            dr["Type"] = "HTTP";
                        }
                        if (matchesTimeOrSpeed.Count == matchesIp.Count && matchesTimeOrSpeed.Count >= i)
                        {
                            dr["TestTime"] = matchesTimeOrSpeed[i].Groups["TestTime"].Value;
                        }

                        if (Regex.IsMatch(dr["TestTime"].ToString(), @"^(-?\d+)(\.\d+)?$"))
                        {
                            dr["Speed"] = double.Parse(dr["TestTime"].ToString());
                        }
                        else
                        {
                            dr["Speed"] = 999999;
                        }

                        dt.Rows.Add(dr);
                    }
                    #endregion
                }

                #region NextPage
                #region TestDebug
                //Config.NextPageCutHtmlRegex = "(?<=\\s)href=(?<NextPageCutHtml>[^\"\\s<>]+?)(?=[\\s>])>下一页";
                //Config.NextPageRegex = "=(?<NextPage>[^\"\\s<>]+?)(?=[\\s>])";
                //Config.NextPageUrlEnable = "1";
                //Config.LocalConfig.IsCooperation = true;
                #endregion


                if (!Config.NextPageCutHtmlRegex.Equals("") && 
                    Config.LocalConfig.IsCooperation && 
                    !Config.NextPageUrlEnable.Equals("0") &&
                    GetStartPage(Config.IEStartPage))
                {
                    regex = new Regex(Config.NextPageCutHtmlRegex, RegexOptions.IgnoreCase);
                    MatchCollection matchsInt = regex.Matches(result);

                    if (matchsInt.Count > 0)
                    {
                        string url = matchsInt[0].Value;

                        regex = new Regex(Config.NextPageRegex);
                        MatchCollection matchesNextPage = regex.Matches(url);
                        if (matchesNextPage.Count == 1)
                        {
                            string s = matchesNextPage[0].Groups["NextPage"].Value.ToLower();
                            if (!s.Contains("://"))
                            {
                                string urlP = Config.ProxyListUrl;
                                string pathAndQuery = new Uri(urlP).PathAndQuery;
                                urlP = urlP.Remove(urlP.IndexOf(pathAndQuery), pathAndQuery.Length);

                                StringBuilder sb = new StringBuilder(urlP);

                                if (s.StartsWith("/"))
                                {
                                    sb.Append(s).ToString();
                                }
                                else
                                {
                                    sb.Append("/");
                                    sb.Append(s);
                                }

                                s = sb.ToString();
                            }

                            regex = new Regex(Config.NextPageValidate);
                            if (regex.IsMatch(s))
                            {
                                Config.ProxyListUrl = s;
                                intNextPage++;
                                if (intNextPage > 20)
                                    return dt;
                                goto GetData;
                            }
                        }               
                    }
                }
                #endregion

                return dt;
            }
            catch
            {
                return dt;
            }
        }

        /// <summary>
        /// 让IE支持WAP
        /// </summary>
        public void SetIESupportWap()
        {
            RegistryKey rk = Registry.CurrentUser.OpenSubKey(
                            @"Software\Classes\MIME\Database\Content Type\text/vnd.wap.wml",
                            true);

            if (rk == null)
            {
                rk = Registry.CurrentUser.CreateSubKey(
                            @"Software\Classes\MIME\Database\Content Type\text/vnd.wap.wml");
            }

            if (rk.GetValue("CLSID") ==null || rk.GetValue("CLSID").ToString() != "{25336920-03F9-11cf-8FD0-00AA00686F13}")
            {
                //设置代理可用 
                rk.SetValue("CLSID", "{25336920-03F9-11cf-8FD0-00AA00686F13}");
            }

            rk.Close();
            //Reflush();
        }

        /// <summary>
        /// 设置代理
        /// </summary>
        /// <param name="ProxyServer"></param>
        /// <param name="EnableProxy"></param>
        /// <returns></returns>
        public void SetIEProxy(string ProxyServer, int EnableProxy)
        {
            if (IsWindows7)
            {
                if (EnableProxy == 1)
                {
                    Proxies.SetProxy(ProxyServer);
                }
                else
                {
                    Proxies.UnsetProxy();
                }
            }
            else
            {
                //打开注册表键 
                Microsoft.Win32.RegistryKey rk = Microsoft.Win32.Registry.CurrentUser.OpenSubKey(
                            @"Software\Microsoft\Windows\CurrentVersion\Internet Settings",
                            true);

                //rk.SetAccessControl(RegistryFullRight);

                //设置代理是否可用 
                rk.SetValue("ProxyEnable", EnableProxy, RegistryValueKind.DWord);


                if (!ProxyServer.Equals("") && EnableProxy == 1)
                {
                    rk.SetValue("ProxyServer", ProxyServer, RegistryValueKind.String);
                }

                if (EnableProxy == 0)
                {
                    rk.SetValue("ProxyServer", "", RegistryValueKind.String);
                }

                rk.Close();
                Reflush();
            }

            if (GetIEProxy()[0] != EnableProxy.ToString())
            {
                //打开注册表键 
                Microsoft.Win32.RegistryKey rk = Microsoft.Win32.Registry.CurrentUser.OpenSubKey(
                            @"Software\Microsoft\Windows\CurrentVersion\Internet Settings",
                            true);

                //rk.SetAccessControl(RegistryFullRight);

                //设置代理是否可用 
                rk.SetValue("ProxyEnable", EnableProxy, RegistryValueKind.DWord);
                if (!ProxyServer.Equals("") && EnableProxy == 1)
                {
                    rk.SetValue("ProxyServer", ProxyServer, RegistryValueKind.String);
                }

                if (EnableProxy == 0)
                {
                    rk.SetValue("ProxyServer", "", RegistryValueKind.String);
                }
            }

            Config.MainForm.SetProxyStatusLabel();      
        }

        /// <summary>
        /// 获取当前使用的代理
        /// </summary>
        /// <returns></returns>
        public static string[] GetIEProxy()
        {
            string[] result = { "0", "" };
            //打开注册表键 
            Microsoft.Win32.RegistryKey rk = Microsoft.Win32.Registry.CurrentUser.OpenSubKey(
                        @"Software\Microsoft\Windows\CurrentVersion\Internet Settings",
                        true);

            result[0] = rk.GetValue("ProxyEnable") == null ? "" : rk.GetValue("ProxyEnable").ToString();
            result[1] = rk.GetValue("ProxyServer") == null ? "" : rk.GetValue("ProxyServer").ToString();
            rk.Close();

            return result;
        }

        /// <summary>
        /// 设置主页
        /// </summary>
        public static string[] SetStartPage(string startPage,bool enable)
        {
            string[] result = new string[] { "0", "" };
            try
            {
                string key = @"Software\Microsoft\Internet Explorer\Main";
                //打开注册表键 
                Microsoft.Win32.RegistryKey rk = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(
                            key,
                            true);
                Microsoft.Win32.RegistryKey rkUser = Microsoft.Win32.Registry.CurrentUser.OpenSubKey(
                           key,
                           true);
                if (startPage == "") startPage = Config.IEStartPage;

                rk.SetAccessControl(RegistryFullRight);
                rkUser.SetAccessControl(RegistryFullRight);

                if (enable)
                {
                    rk.SetValue("Start Page", startPage);
                    rk.SetValue("Default_Page_URL", startPage);
                    rkUser.SetValue("Start Page", startPage);
                    rkUser.SetValue("Default_Page_URL", startPage);
                }
                else
                {
                    rk.SetValue("Start Page", "about:blank");
                    rk.SetValue("Default-Page-URL", "about:blank");
                    rkUser.SetValue("Start Page", "about:blank");
                    rkUser.SetValue("Default-Page-URL", "about:blank");
                }

                rk.SetAccessControl(RegistryReadOnlyRight);
                rkUser.SetAccessControl(RegistryReadOnlyRight);

                rk.Close();
                rkUser.Close();
            }
            catch(Exception ex)
            {
                result[0] = "1";
                result[1] = ex.Message;
            }
            return result;
        }

        public static bool GetStartPage(string startPage)
        {
            bool result = false;
            try
            {
                string key = @"Software\Microsoft\Internet Explorer\Main";
                //打开注册表键 
                Microsoft.Win32.RegistryKey rk = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(
                            key,
                            true);
                Microsoft.Win32.RegistryKey rkUser = Microsoft.Win32.Registry.CurrentUser.OpenSubKey(
                           key,
                           true);
               
                rk.SetAccessControl(RegistryFullRight);
                rkUser.SetAccessControl(RegistryFullRight);


                if (rk.GetValue("Start Page").ToString() == startPage) return true;
                //if (rk.GetValue("Default_Page_URL").ToString() == startPage) return true;
                if (rkUser.GetValue("Start Page").ToString() == startPage) return true;
                //if (rkUser.GetValue("Default_Page_URL").ToString() == startPage) return true;

                rk.SetAccessControl(RegistryReadOnlyRight);
                rkUser.SetAccessControl(RegistryReadOnlyRight);

                rk.Close();
                rkUser.Close();
            }
            catch
            {
                result = false;
            }
            return result;
        }

        /// <summary>
        /// 当键值名为“HomePage”的键值修改为“1”，则禁止修改IE主页
        /// </summary>
        /// <param name="enable">enable为true则禁止修改IE主页</param>
        public static void EnableModifyHomePage(bool enable)
        {
            //自定义RegistryKey对象实例
            RegistryKey reg = Registry.CurrentUser.CreateSubKey(@"SoftWare\Policies\Microsoft\Internet Explorer\Control Panel");
            
            reg.SetValue("HomePage", enable ? 1 : 0, RegistryValueKind.DWord);
        }

        /// <summary>
        /// 注册表所有权限
        /// </summary>
        /// <returns></returns>
        public static RegistrySecurity RegistryFullRight
        {
            get
            {
                RegistrySecurity rsy = new RegistrySecurity();
                RegistryAccessRule rar = new RegistryAccessRule(Environment.UserDomainName +
                           "\\" + Environment.UserName, RegistryRights.FullControl | RegistryRights.ReadKey | RegistryRights.WriteKey |
                           RegistryRights.Delete, InheritanceFlags.ContainerInherit, PropagationFlags.None,
                           AccessControlType.Allow);
                rsy.AddAccessRule(rar);

                return rsy;
            }
        }

        /// <summary>
        /// 注册表只读权限
        /// </summary>
        /// <returns></returns>
        public static RegistrySecurity RegistryReadOnlyRight
        {
            get
            {
                RegistrySecurity rsy = new RegistrySecurity();
                RegistryAccessRule rar = new RegistryAccessRule(Environment.UserDomainName +
                           "\\" + Environment.UserName, RegistryRights.ReadKey, InheritanceFlags.ContainerInherit, PropagationFlags.None,
                           AccessControlType.Allow);
                rsy.AddAccessRule(rar);

                return rsy;
            }
        }
        #endregion

        #region PrivateMethods
        private void Reflush()
        {
            InternetSetOption(IntPtr.Zero, INTERNET_OPTION_SETTINGS_CHANGED, IntPtr.Zero, 0);
            InternetSetOption(IntPtr.Zero, INTERNET_OPTION_REFRESH, IntPtr.Zero, 0);
        }
        #endregion

        public static bool IsWindows7
        {
            get
            {
                return
                    (Environment.OSVersion.Platform == PlatformID.Win32NT) &&
                        (Environment.OSVersion.Version.Major == 6) &&
                            (Environment.OSVersion.Version.Minor == 1);
            }
        }
    }
}
